/*
 * Copyright (C) 2020  Prasoon Joshi
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package models

import generated._
import graphql.SchemaDefinition.FreeText
import scalaxb.DataRecord


//TODO: Do we need to cover "_" cases?
object Resolvers {
  def audienceResolver(audience: Option[Audience]) =
    audience match {
      case Some(External) => External.toString
      case Some(Internal) => Internal.toString
    }

  def uriResolver(url: Option[java.net.URI]) =
    url match {
      case Some(url) => url.toString
      case _ => "" //TODO: Should this return an empty string instead of a None?
    }

  def langencodingResolver(langEncoding: Option[Langencoding]) =
    langEncoding match {
      case Some(Iso639u452b) => Iso639u452b.toString
      case Some(Iso639u453) => Iso639u453.toString
      case Some(Otherlangencoding) => Otherlangencoding.toString
    }

  def scriptEncodingResolver(scriptEncoding: Option[Scriptencoding]) =
    scriptEncoding match {
      case Some(Iso15924) => Iso15924.toString
      case Some(Otherscriptencoding) => Otherscriptencoding.toString
    }

  def dateEncodingResolver(dateEncoding: Option[Dateencoding]) =
    dateEncoding match {
      case Some(Iso8601) => Iso8601.toString
      case Some(Otherdateencoding) => Otherdateencoding.toString
    }

  def countryEncodingResolver(countryEncoding: Option[Countryencoding]) =
    countryEncoding match {
      case Some(Iso3166u451) => Iso3166u451.toString
      case Some(Othercountryencoding) => Othercountryencoding.toString
    }

  def repositoryEncodingResolver(repositoryEncoding: Option[Repositoryencoding]) =
    repositoryEncoding match {
      case Some(Iso15511) => Iso15511.toString
      case Some(Otherrepositoryencoding) => Otherrepositoryencoding.toString
    }

  def levelTypeResolver(level: LevelType) =
    level match {
      case ClassValue => ClassValue.toString
      case CollectionValue => CollectionValue.toString
      case FileValue => FileValue.toString
      case FondsValue => FondsValue.toString
      case ItemValue2 => ItemValue2.toString
      case OtherlevelValue => OtherlevelValue.toString
      case RecordgrpValue => RecordgrpValue.toString
      case SeriesValue => SeriesValue.toString
      case SubfondsValue => SubfondsValue.toString
      case SubgrpValue => SubgrpValue.toString
      case SubseriesValue => SubseriesValue.toString
    }

  def showTypeResolver(showType: Option[ShowType]) =
    showType match {
      case Some(NewValue2) => NewValue2.toString
      case Some(ReplaceValue) => ReplaceValue.toString
      case Some(EmbedValue) => EmbedValue.toString
      case Some(OtherValue2) => OtherValue2.toString
      case Some(NoneTypeValue4) => NoneTypeValue4.toString
      case None => "" //TODO: Could this be defaulted to NoneTypeValue4?
    }

  def showResolver(show: Option[Show]) = show match {
    case Some(s) => s.toString
    case None => NoneTypeValue2.toString
  }

  def actuateTypeResolver(actuateType: Option[ActuateType]) =
    actuateType match {
      case Some(OnloadValue) => OnloadValue.toString
      case Some(OnrequestValue) => OnrequestValue.toString
      case Some(OtherValue3) => OtherValue3.toString
      case Some(NoneTypeValue5) => NoneTypeValue5.toString
      case None => "" //TODO: Could this be defaulted to NoneTypeValue5?
    }

  def actuateResolver(actuate: Option[Actuate]) = actuate match {
    case Some(a) => a.toString
    case None => NoneTypeValue3.toString
  }

  def renderResolver(render: Option[Render]) =
    render match {
      case Some(Altrender) => Altrender.toString
      case Some(Bold) => Bold.toString
      case Some(Bolddoublequote) => Bolddoublequote.toString
      case Some(Bolditalic) => Bolditalic.toString
      case Some(Boldsinglequote) => Boldsinglequote.toString
      case Some(Boldsmcaps) => Boldsmcaps.toString
      case Some(Boldunderline) => Boldunderline.toString
      case Some(Doublequote) => Doublequote.toString
      case Some(Italic) => Italic.toString
      case Some(Nonproport) => Nonproport.toString
      case Some(Singlequote) => Singlequote.toString
      case Some(Smcaps) => Smcaps.toString
      case Some(Sub) => Sub.toString
      case Some(Super) => Super.toString
      case Some(Underline) => Underline.toString
      case None => ""
    }

  def valueTypeResolver(valueType: ValueType) =
    valueType match {
      case Inprocess => Inprocess.toString
      case Approved => Approved.toString
      case Published => Published.toString
    }

  def valueType2Resolver(valueType2: ValueType2) = valueType2 match {
    case value => value.toString
  }

  def valueType3Resolver(valueType3: ValueType3) = valueType3 match {
    case value => value.toString
  }

  def valueResolver(value: Value) =
    value match {
      case Revised => Revised.toString
      case Deleted => Deleted.toString
      case New => New.toString
      case Deletedsplit => Deletedsplit.toString
      case Deletedmerged => Deletedmerged.toString
      case Deletedreplaced => Deletedreplaced.toString
      case Cancelled => Cancelled.toString
      case Derived => Derived.toString
    }

  def archDescOptionResolver(archdescoption: Seq[scalaxb.DataRecord[Any]]) =
    archdescoption.map(p => p.value)

  def dataRecordResolver[A](archdescoption: Seq[scalaxb.DataRecord[Any]]) =
    archdescoption.find({p => p.value.isInstanceOf[A]}) match {
      case Some(DataRecord(_, _, value)) => Some(value)
      case None => None
    }

  def avBooleanResolver(avBooleanOption: Option[Avu46boolean]) =
    avBooleanOption.map(p => p match {
      case True => true
      case False => false
    })

  def mMixedBasicElementsOptionResolver(mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.value match {
      case a: Abbr => a
      case em: Emph => em
      case ex: Expan => ex
      case f: Foreign => f
      case lb: Lb => lb
      case p: Ptr => p
      case ref: Ref => ref
      case s: String => FreeText(s)
    })

  def mixedElementsResolver(mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.value match {
      case a: String => FreeText(a)
      case b => b
    })

  def mMixedBasicDateElementsOption1Resolver(mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.value match {
      case a: Abbr => a
      case em: Emph => em
      case ex: Expan => ex
      case f: Foreign => f
      case lb: Lb => lb
      case ptr: Ptr => ptr
      case ref: Ref => ref
      case s: String => FreeText(s)
    })

  def mBlocksOptionResolver(options: Seq[scalaxb.DataRecord[Any]]) =
    options.map(p => p.value match {
      case b: Blockquote => b
      case c: Chronlist => c
      case l: ListType => l
      case p: P => p
      case t: Table => t
    })

  //    def mixedDataRecordOptionsResolver[A](mixed: Seq[scalaxb.DataRecord[A]]) =
  //      mixed.map(p => p.value)

  def mixedDataRecordOptionsResolver[A](mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.value.asInstanceOf[A]) //TODO: Change such access. See below.

  def textDataRecordResolver[A](mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.as[A])

  def accessRestrictOptionResolver(accessRestrictOptions: Seq[scalaxb.DataRecord[Any]]) =
    accessRestrictOptions.map(p => p.value match {
      case a: Accessrestrict => a
      case b: Blockquote => b
      case c: Chronlist => c
      case h: Head => h
      case l: ListType => l
      case p: P => p
      case t: Table => t
    })

  def blockquoteOptionResolver(blockquoteOptions: Seq[scalaxb.DataRecord[Any]]) =
    blockquoteOptions.map(p => p.value match {
      case c: Chronlist => c
      case l: ListType => l
      case p: P => p
      case t: Table => t
    })

  def seriesstmtOptionResolver(seriesstmtoption: Seq[scalaxb.DataRecord[SeriesstmtOption]]) =
    seriesstmtoption.map(p => p.value match {
      case t: Titleproper => t
      case n: Num => n
      case p: P => p
    })

  def mMixedBasicElementsOption1Resolver(options: Seq[scalaxb.DataRecord[Any]]) =
    options.map(p => p.value match {
      case s: String => FreeText(s)
        //TODO: Handle exception cases for none of the below
      case a: Abbr => a
      case e: Emph => e
      case ex: Expan => ex
      case f: Foreign => f
      case l: Lb => l
      case p: Ptr => p
      case r: Ref => r
    })

  def mParaContentableOptionResolver(options: Seq[scalaxb.DataRecord[Any]]) =
    options.map(p => p.value match {
      case a: Abbr => a
      case c: Corpname => c
      case d: Date => d
      case e: Emph => e
      case ex: Expan => ex
      case f: Famname => f
      case fo: Footnote => fo
      case foreign: Foreign => foreign
      case fun: FunctionType => fun
      case gen: Genreform => gen
      case geo: Geogname => geo
      case lb: Lb => lb
      case list: ListType => list
      case name: Name => name
      case num: Num => num
      case occ: Occupation => occ
      case per: Persname => per
      case ptr: Ptr => ptr
      case quote: Quote => quote
      case ref: Ref => ref
      case sub: Subject => sub
      case title: Title => title
      case str: String => FreeText(str)
    })

  def chronitemOptionResolver(option: scalaxb.DataRecord[ChronitemOption]) = option.value

  def chronitemOption2Resolver(option: Seq[scalaxb.DataRecord[ChronitemOption2]]) =
    option.map(p => p.value match {
      case seq: ChronitemSequence1 => seq
      case set: Chronitemset => set
    })

  def datesetOptionResolver(option: scalaxb.DataRecord[DatesetOption]) = option.value

  def datesetOption2Resolver(options: Seq[scalaxb.DataRecord[DatesetOption2]]) =
    options.map(p => p.value match {
      case date: Datesingle => date
      case range: Daterange => range
    })

  def listTypeOptionTypeResolver(options: Seq[scalaxb.DataRecord[ListTypeOption]]) =
    options.map(p => p.value match {
      case item: Item => item
      case seq: ListTypeSequence1 => seq
    })

  def mRefOptionResolver(mixed: Seq[scalaxb.DataRecord[Any]]) =
    mixed.map(p => p.value match {
      case s: String => FreeText(s)
      case a: Abbr => a
      case c: Corpname => c
      case d: Date => d
      case e: Emph => e
      case ex: Expan => ex
      case f: Famname => f
      case fo: Footnote => fo
      case fn: FunctionType => fn
      case ge: Genreform => ge
      case geo: Geogname => geo
      case l: Lb => l
      case n: Name => n
      case nu: Num => nu
      case oc: Occupation => oc
      case pe: Persname => pe
      case ptr: Ptr => ptr
      case quote: Quote => quote
      case sub: Subject => sub
      case tit: Title => tit
    })

  def renderTypeResolver(render: Option[RenderType]): String = render match {
    case Some(AltrenderValue) => AltrenderValue.toString
    case Some(BoldValue) => BoldValue.toString
    case Some(BolddoublequoteValue) => BolddoublequoteValue.toString
    case Some(BolditalicValue) => BolditalicValue.toString
    case Some(BoldsinglequoteValue) => BoldsinglequoteValue.toString
    case Some(BoldsmcapsValue) => BoldsmcapsValue.toString
    case Some(BoldunderlineValue) => BoldunderlineValue.toString
    case Some(DoublequoteValue) => DoublequoteValue.toString
    case Some(ItalicValue) => ItalicValue.toString
    case Some(NonproportValue) => NonproportValue.toString
    case Some(SinglequoteValue) => SinglequoteValue.toString
    case Some(SmcapsValue) => SmcapsValue.toString
    case Some(SubValue) => SubValue.toString
    case Some(SuperValue) => SuperValue.toString
    case Some(UnderlineValue) => UnderlineValue.toString
  }

  def renderType2Resolver(render: Option[RenderType2]): String = render match {
    case Some(r) => r.toString
    case None => ""
  }

  def alignTypeResolver(align: Option[AlignType]): String = align match {
    case Some(a) => a.toString
    case None => ""
  }

  def valignType3Resolver(valign: Option[ValignType3]): Option[String] = valign.map(p => p.toString)

  def typeToStringResolver[A](valign: Option[A]): Option[String] = valign.map(_.toString)

  def renderType3Resolver(render: Option[RenderType3]): String = render match {
    case Some(AltrenderValue3) => AltrenderValue3.toString
    case Some(BoldValue3) => BoldValue3.toString
    case Some(BolddoublequoteValue3) => BolddoublequoteValue3.toString
    case Some(BolditalicValue3) => BolditalicValue3.toString
    case Some(BoldsinglequoteValue3) => BoldsinglequoteValue3.toString
    case Some(BoldsmcapsValue3) => BoldsmcapsValue3.toString
    case Some(BoldunderlineValue3) => BoldunderlineValue3.toString
    case Some(DoublequoteValue3) => DoublequoteValue3.toString
    case Some(ItalicValue3) => ItalicValue3.toString
    case Some(NonproportValue3) => NonproportValue3.toString
    case Some(SinglequoteValue3) => SinglequoteValue3.toString
    case Some(SmcapsValue3) => SmcapsValue3.toString
    case Some(SubValue3) => SubValue3.toString
    case Some(SuperValue3) => SuperValue3.toString
    case Some(UnderlineValue3) => UnderlineValue3.toString
  }

  def renderType4Resolver(render: Option[RenderType4]): String = render match {
    case Some(r) => r.toString
    case None => ""
  }

  def localControlOptionResolver(option: Option[DataRecord[LocalcontrolOption]]) =
    option.map(p => p.value)

}